home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / sh03src.zoo / sh-pl03 / sh / jobs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-23  |  22.3 KB  |  1,041 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)jobs.c    5.1 (Berkeley) 3/7/91";
  39. #endif /* not lint */
  40.  
  41. #include "shell.h"
  42. #if JOBS
  43. #include "sgtty.h"
  44. #undef CEOF            /* syntax.h redefines this */
  45. #endif
  46. #include "main.h"
  47. #include "parser.h"
  48. #include "nodes.h"
  49. #include "jobs.h"
  50. #include "options.h"
  51. #include "trap.h"
  52. #include "signames.h"
  53. #include "syntax.h"
  54. #include "input.h"
  55. #include "output.h"
  56. #include "memalloc.h"
  57. #include "error.h"
  58. #include "mystring.h"
  59. #include "redir.h"
  60. #include <fcntl.h>
  61. #include <signal.h>
  62. #include <errno.h>
  63. #ifdef BSD
  64. #include <sys/types.h>
  65. #include <sys/wait.h>
  66. #include <sys/time.h>
  67. #include <sys/resource.h>
  68. #endif
  69.  
  70.  
  71.  
  72. struct job *jobtab;        /* array of jobs */
  73. int njobs;            /* size of array */
  74. MKINIT short backgndpid = -1;    /* pid of last background process */
  75. #if JOBS
  76. int initialpgrp;        /* pgrp of shell on invocation */
  77. short curjob;            /* current job */
  78. #endif
  79.  
  80. #ifdef __STDC__
  81. STATIC void restartjob(struct job *);
  82. STATIC struct job *getjob(char *);
  83. STATIC void freejob(struct job *);
  84. STATIC int procrunning(int);
  85. STATIC int dowait(int, struct job *);
  86. STATIC int waitproc(int, int *);
  87. STATIC char *commandtext(union node *);
  88. #else
  89. STATIC void restartjob();
  90. STATIC struct job *getjob();
  91. STATIC void freejob();
  92. STATIC int procrunning();
  93. STATIC int dowait();
  94. STATIC int waitproc();
  95. STATIC char *commandtext();
  96. #endif
  97.  
  98.  
  99.  
  100. #if JOBS
  101. /*
  102.  * Turn job control on and off.
  103.  *
  104.  * Note:  This code assumes that the third arg to ioctl is a character
  105.  * pointer, which is true on Berkeley systems but not System V.  Since
  106.  * System V doesn't have job control yet, this isn't a problem now.
  107.  */
  108.  
  109. MKINIT int jobctl;
  110.  
  111. void
  112. setjobctl(on) {
  113.     int ldisc;
  114.  
  115.     if (on == jobctl || rootshell == 0)
  116.         return;
  117.     if (on) {
  118.         do { /* while we are in the background */
  119.             if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
  120.                 out2str("ash: can't access tty; job control turned off\n");
  121.                 jflag = 0;
  122.                 return;
  123.             }
  124.             if (initialpgrp == -1)
  125.                 initialpgrp = getpgrp(0);
  126.             else if (initialpgrp != getpgrp(0)) {
  127.                 killpg(initialpgrp, SIGTTIN);
  128.                 continue;
  129.             }
  130.         } while (0);
  131.         if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
  132.             out2str("ash: need new tty driver to run job control; job control turned off\n");
  133.             jflag = 0;
  134.             return;
  135.         }
  136.         setsignal(SIGTSTP);
  137.         setsignal(SIGTTOU);
  138.         setpgrp(0, rootpid);
  139.         ioctl(2, TIOCSPGRP, (char *)&rootpid);
  140.     } else { /* turning job control off */
  141.         setpgrp(0, initialpgrp);
  142.         ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
  143.         setsignal(SIGTSTP);
  144.         setsignal(SIGTTOU);
  145.     }
  146.     jobctl = on;
  147. }
  148. #endif
  149.  
  150.  
  151. #ifdef mkinit
  152.  
  153. SHELLPROC {
  154.     backgndpid = -1;
  155. #if JOBS
  156.     jobctl = 0;
  157. #endif
  158. }
  159.  
  160. #endif
  161.  
  162.  
  163.  
  164. #if JOBS
  165. fgcmd(argc, argv)  char **argv; {
  166.     struct job *jp;
  167.     int pgrp;
  168.     int status;
  169.  
  170.     jp = getjob(argv[1]);
  171.     if (jp->jobctl == 0)
  172.         error("job not created under job control");
  173.     pgrp = jp->ps[0].pid;
  174.     ioctl(2, TIOCSPGRP, (char *)&pgrp);
  175.     restartjob(jp);
  176.     INTOFF;
  177.     status = waitforjob(jp);
  178.     INTON;
  179.     return status;
  180. }
  181.  
  182.  
  183. bgcmd(argc, argv)  char **argv; {
  184.     struct job *jp;
  185.  
  186.     do {
  187.         jp = getjob(*++argv);
  188.         if (jp->jobctl == 0)
  189.             error("job not created under job control");
  190.         restartjob(jp);
  191.     } while (--argc > 1);
  192.     return 0;
  193. }
  194.  
  195.  
  196. STATIC void
  197. restartjob(jp)
  198.     struct job *jp;
  199.     {
  200.     struct procstat *ps;
  201.     int i;
  202.  
  203.     if (jp->state == JOBDONE)
  204.         return;
  205.     INTOFF;
  206.     killpg(jp->ps[0].pid, SIGCONT);
  207.     for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
  208.         if ((ps->status & 0377) == 0177) {
  209.             ps->status = -1;
  210.             jp->state = 0;
  211.         }
  212.     }
  213.     INTON;
  214. }
  215. #endif
  216.  
  217.  
  218. int
  219. jobscmd(argc, argv)  char **argv; {
  220.     showjobs(0);
  221.     return 0;
  222. }
  223.  
  224.  
  225. /*
  226.  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
  227.  * statuses have changed since the last call to showjobs.
  228.  *
  229.  * If the shell is interrupted in the process of creating a job, the
  230.  * result may be a job structure containing zero processes.  Such structures
  231.  * will be freed here.
  232.  */
  233.  
  234. void
  235. showjobs(change) {
  236.     int jobno;
  237.     int procno;
  238.     int i;
  239.     struct job *jp;
  240.     struct procstat *ps;
  241.     int col;
  242.     char s[64];
  243.  
  244.     TRACE(("showjobs(%d) called\n", change));
  245.     while (dowait(0, (struct job *)NULL) > 0);
  246.     for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
  247.         if (! jp->used)
  248.             continue;
  249.         if (jp->nprocs == 0) {
  250.             freejob(jp);
  251.             continue;
  252.         }
  253.         if (change && ! jp->changed)
  254.             continue;
  255.         procno = jp->nprocs;
  256.         for (ps = jp->ps ; ; ps++) {    /* for each process */
  257.             if (ps == jp->ps)
  258.                 fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
  259.             else
  260.                 fmtstr(s, 64, "    %d ", ps->pid);
  261.             out1str(s);
  262.             col = strlen(s);
  263.             s[0] = '\0';
  264.             if (ps->status == -1) {
  265.                 /* don't print anything */
  266.             } else if ((ps->status & 0xFF) == 0) {
  267.                 fmtstr(s, 64, "Exit %d", ps->status >> 8);
  268.             } else {
  269.                 i = ps->status;
  270. #if JOBS
  271.                 if ((i & 0xFF) == 0177)
  272.                     i >>= 8;
  273. #endif
  274.                 if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F])
  275.                     scopy(sigmesg[i & 0x7F], s);
  276.                 else
  277.                     fmtstr(s, 64, "Signal %d", i & 0x7F);
  278.                 if (i & 0x80)
  279.                     strcat(s, " (core dumped)");
  280.             }
  281.             out1str(s);
  282.             col += strlen(s);
  283.             do {
  284.                 out1c(' ');
  285.                 col++;
  286.             } while (col < 30);
  287.             out1str(ps->cmd);
  288.             out1c('\n');
  289.             if (--procno <= 0)
  290.                 break;
  291.         }
  292.         jp->changed = 0;
  293.         if (jp->state == JOBDONE) {
  294.             freejob(jp);
  295.         }
  296.     }
  297. }
  298.  
  299.  
  300. /*
  301.  * Mark a job structure as unused.
  302.  */
  303.  
  304. STATIC void
  305. freejob(jp)
  306.     struct job *jp;
  307.     {
  308.     struct procstat *ps;
  309.     int i;
  310.  
  311.     INTOFF;
  312.     for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
  313.         if (ps->cmd != nullstr)
  314.             ckfree(ps->cmd);
  315.     }
  316.     if (jp->ps != &jp->ps0)
  317.         ckfree(jp->ps);
  318.     jp->used = 0;
  319. #if JOBS
  320.     if (curjob == jp - jobtab + 1)
  321.         curjob = 0;
  322. #endif
  323.     INTON;
  324. }
  325.  
  326.  
  327.  
  328. int
  329. waitcmd(argc, argv)  char **argv; {
  330.     struct job *job;
  331.     int status;
  332.     struct job *jp;
  333.  
  334.     if (argc > 1) {
  335.         job = getjob(argv[1]);
  336.     } else {
  337.         job = NULL;
  338.     }
  339.     for (;;) {    /* loop until process terminated or stopped */
  340.         if (job != NULL) {
  341.             if (job->state) {
  342.                 status = job->ps[job->nprocs - 1].status;
  343.                 if ((status & 0xFF) == 0)
  344.                     status = status >> 8 & 0xFF;
  345. #if JOBS
  346.                 else if ((status & 0xFF) == 0177)
  347.                     status = (status >> 8 & 0x7F) + 128;
  348. #endif
  349.                 else
  350.                     status = (status & 0x7F) + 128;
  351.                 if (! iflag)
  352.                     freejob(job);
  353.                 return status;
  354.             }
  355.         } else {
  356.             for (jp = jobtab ; ; jp++) {
  357.                 if (jp >= jobtab + njobs) {    /* no running procs */
  358.                     return 0;
  359.                 }
  360.                 if (jp->used && jp->state == 0)
  361.                     break;
  362.             }
  363.         }
  364.         dowait(1, (struct job *)NULL);
  365.     }
  366. }
  367.  
  368.  
  369.  
  370. jobidcmd(argc, argv)  char **argv; {
  371.     struct job *jp;
  372.     int i;
  373.  
  374.     jp = getjob(argv[1]);
  375.     for (i = 0 ; i < jp->nprocs ; ) {
  376.         out1fmt("%d", jp->ps[i].pid);
  377.         out1c(++i < jp->nprocs? ' ' : '\n');
  378.     }
  379.     return 0;
  380. }
  381.  
  382.  
  383.  
  384. /*
  385.  * Convert a job name to a job structure.
  386.  */
  387.  
  388. STATIC struct job *
  389. getjob(name)
  390.     char *name;
  391.     {
  392.     int jobno;
  393.     register struct job *jp;
  394.     int pid;
  395.     int i;
  396.  
  397.     if (name == NULL) {
  398. #if JOBS
  399. currentjob:
  400.         if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
  401.             error("No current job");
  402.         return &jobtab[jobno - 1];
  403. #else
  404.         error("No current job");
  405. #endif
  406.     } else if (name[0] == '%') {
  407.         if (is_digit(name[1])) {
  408.             jobno = number(name + 1);
  409.             if (jobno > 0 && jobno <= njobs
  410.              && jobtab[jobno - 1].used != 0)
  411.                 return &jobtab[jobno - 1];
  412. #if JOBS
  413.         } else if (name[1] == '%' && name[2] == '\0') {
  414.             goto currentjob;
  415. #endif
  416.         } else {
  417.             register struct job *found = NULL;
  418.             for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
  419.                 if (jp->used && jp->nprocs > 0
  420.                  && prefix(name + 1, jp->ps[0].cmd)) {
  421.                     if (found)
  422.                         error("%s: ambiguous", name);
  423.                     found = jp;
  424.                 }
  425.             }
  426.             if (found)
  427.                 return found;
  428.         }
  429.     } else if (is_number(name)) {
  430.         pid = number(name);
  431.         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
  432.             if (jp->used && jp->nprocs > 0
  433.              && jp->ps[jp->nprocs - 1].pid == pid)
  434.                 return jp;
  435.         }
  436.     }
  437.     error("No such job: %s", name);
  438. }
  439.  
  440.  
  441.  
  442. /*
  443.  * Return a new job structure,
  444.  */
  445.  
  446. struct job *
  447. makejob(node, nprocs)
  448.     union node *node;
  449.     {
  450.     int i;
  451.     struct job *jp;
  452.  
  453.     for (i = njobs, jp = jobtab ; ; jp++) {
  454.         if (--i < 0) {
  455.             INTOFF;
  456.             if (njobs == 0) {
  457.                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
  458.             } else {
  459.                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
  460.                 bcopy(jobtab, jp, njobs * sizeof jp[0]);
  461.                 ckfree(jobtab);
  462.                 jobtab = jp;
  463.             }
  464.             jp = jobtab + njobs;
  465.             for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
  466.             INTON;
  467.             break;
  468.         }
  469.         if (jp->used == 0)
  470.             break;
  471.     }
  472.     INTOFF;
  473.     jp->state = 0;
  474.     jp->used = 1;
  475.     jp->changed = 0;
  476.     jp->nprocs = 0;
  477. #if JOBS
  478.     jp->jobctl = jobctl;
  479. #endif
  480.     if (nprocs > 1) {
  481.         jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
  482.     } else {
  483.         jp->ps = &jp->ps0;
  484.     }
  485.     INTON;
  486.     TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1));
  487.     return jp;
  488. }    
  489.  
  490.  
  491. /*
  492.  * Fork of a subshell.  If we are doing job control, give the subshell its
  493.  * own process group.  Jp is a job structure that the job is to be added to.
  494.  * N is the command that will be evaluated by the child.  Both jp and n may
  495.  * be NULL.  The mode parameter can be one of the following:
  496.  *    FORK_FG - Fork off a foreground process.
  497.  *    FORK_BG - Fork off a background process.
  498.  *    FORK_NOJOB - Like FORK_FG, but don't give the process its own
  499.  *             process group even if job control is on.
  500.  *
  501.  * When job control is turned off, background processes have their standard
  502.  * input redirected to /dev/null (except for the second and later processes
  503.  * in a pipeline).
  504.  */
  505.  
  506. int
  507. forkshell(jp, n, mode)
  508.     union node *n;
  509.     struct job *jp;
  510.     {
  511.     int pid;
  512.     int pgrp;
  513. #ifdef __MINT__
  514.     int fd;
  515. #endif
  516.  
  517.     TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode));
  518.     INTOFF;
  519.     pid = fork();
  520.     if (pid == -1) {
  521.         TRACE(("Fork failed, errno=%d\n", errno));
  522.         INTON;
  523.         error("Cannot fork");
  524.     }
  525.     if (pid == 0) {
  526.         struct job *p;
  527.         int wasroot;
  528.         int i;
  529.  
  530.         TRACE(("Child shell %d\n", getpid()));
  531.         wasroot = rootshell;
  532.         rootshell = 0;
  533.         for (i = njobs, p = jobtab ; --i >= 0 ; p++)
  534.             if (p->used)
  535.                 freejob(p);
  536.         closescript();
  537.         INTON;
  538.         clear_traps();
  539. #if JOBS
  540.         jobctl = 0;        /* do job control only in root shell */
  541.         if (wasroot && mode != FORK_NOJOB && jflag) {
  542.             if (jp == NULL || jp->nprocs == 0)
  543.                 pgrp = getpid();
  544.             else
  545.                 pgrp = jp->ps[0].pid;
  546.             setpgrp(0, pgrp);
  547.             if (mode == FORK_FG) {
  548.                 /*** this causes superfluous TIOCSPGRPS ***/
  549.                 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
  550.                     error("TIOCSPGRP failed, errno=%d\n", errno);
  551.             }
  552.             setsignal(SIGTSTP);
  553.             setsignal(SIGTTOU);
  554.         } else if (mode == FORK_BG) {
  555.             ignoresig(SIGINT);
  556.             ignoresig(SIGQUIT);
  557.             if ((jp == NULL || jp->nprocs == 0)
  558.                 && ! fd0_redirected_p ()) {
  559.                 close(0);
  560. #ifndef __MINT__
  561.                 if (open("/dev/null", O_RDONLY) != 0)
  562.                     error("Can't open /dev/null");
  563. #else
  564.                 if ((fd = open("/dev/null", O_RDONLY)) < 0)
  565.                     error("Can't open /dev/null");
  566.                 else {
  567.                     dup2(fd, 0);
  568.                     close(fd);
  569.                 }
  570. #endif
  571.             }
  572.         }
  573. #else
  574.         if (mode == FORK_BG) {
  575.             ignoresig(SIGINT);
  576.             ignoresig(SIGQUIT);
  577.             if ((jp == NULL || jp->nprocs == 0)
  578.                 && ! fd0_redirected_p ()) {
  579.                 close(0);
  580. #ifndef __MINT__
  581.                 if (open("/dev/null", O_RDONLY) != 0)
  582.                     error("Can't open /dev/null");
  583. #else
  584.                 if ((fd = open("/dev/null", O_RDONLY)) < 0)
  585.                     error("Can't open /dev/null");
  586.                 else {
  587.                     dup2(fd, 0);
  588.                     close(fd);
  589.                 }
  590. #endif
  591.             }
  592.         }
  593. #endif
  594.         if (wasroot && iflag) {
  595.             setsignal(SIGINT);
  596.             setsignal(SIGQUIT);
  597.             setsignal(SIGTERM);
  598.         }
  599.         return pid;
  600.     }
  601.     if (rootshell && mode != FORK_NOJOB && jflag) {
  602.         if (jp == NULL || jp->nprocs == 0)
  603.             pgrp = pid;
  604.         else
  605.             pgrp = jp->ps[0].pid;
  606.         setpgrp(pid, pgrp);
  607.     }
  608.     if (mode == FORK_BG)
  609.         backgndpid = pid;        /* set $! */
  610.     if (jp) {
  611.         struct procstat *ps = &jp->ps[jp->nprocs++];
  612.         ps->pid = pid;
  613.         ps->status = -1;
  614.         ps->cmd = nullstr;
  615.         if (iflag && rootshell && n)
  616.             ps->cmd = commandtext(n);
  617.     }
  618.     INTON;
  619.     TRACE(("In parent shell:  child = %d\n", pid));
  620.     return pid;
  621. }
  622.  
  623.  
  624.  
  625. /*
  626.  * Wait for job to finish.
  627.  *
  628.  * Under job control we have the problem that while a child process is
  629.  * running interrupts generated by the user are sent to the child but not
  630.  * to the shell.  This means that an infinite loop started by an inter-
  631.  * active user may be hard to kill.  With job control turned off, an
  632.  * interactive user may place an interactive program inside a loop.  If
  633.  * the interactive program catches interrupts, the user doesn't want
  634.  * these interrupts to also abort the loop.  The approach we take here
  635.  * is to have the shell ignore interrupt signals while waiting for a
  636.  * forground process to terminate, and then send itself an interrupt
  637.  * signal if the child process was terminated by an interrupt signal.
  638.  * Unfortunately, some programs want to do a bit of cleanup and then
  639.  * exit on interrupt; unless these processes terminate themselves by
  640.  * sending a signal to themselves (instead of calling exit) they will
  641.  * confuse this approach.
  642.  */
  643.  
  644. int
  645. waitforjob(jp)
  646.     register struct job *jp;
  647.     {
  648. #if JOBS
  649.     int mypgrp = getpgrp(0);
  650. #endif
  651.     int status;
  652.     int st;
  653.  
  654.     INTOFF;
  655.     TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
  656.     while (jp->state == 0) {
  657.         dowait(1, jp);
  658.     }
  659. #if JOBS
  660.     if (jp->jobctl) {
  661.         if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
  662.             error("TIOCSPGRP failed, errno=%d\n", errno);
  663.     }
  664.     if (jp->state == JOBSTOPPED)
  665.         curjob = jp - jobtab + 1;
  666. #endif
  667.     status = jp->ps[jp->nprocs - 1].status;
  668.     /* convert to 8 bits */
  669.     if ((status & 0xFF) == 0)
  670.         st = status >> 8 & 0xFF;
  671. #if JOBS
  672.     else if ((status & 0xFF) == 0177)
  673.         st = (status >> 8 & 0x7F) + 128;
  674. #endif
  675.     else
  676.         st = (status & 0x7F) + 128;
  677.     if (! JOBS || jp->state == JOBDONE)
  678.         freejob(jp);
  679.     CLEAR_PENDING_INT;
  680.     if ((status & 0x7F) == SIGINT)
  681.         kill(getpid(), SIGINT);
  682.     INTON;
  683.     return st;
  684. }
  685.  
  686.  
  687.  
  688. /*
  689.  * Wait for a process to terminate.
  690.  */
  691.  
  692. STATIC int
  693. dowait(block, job)
  694.     struct job *job;
  695.     {
  696.     int pid;
  697.     int status;
  698.     struct procstat *sp;
  699.     struct job *jp;
  700.     struct job *thisjob;
  701.     int done;
  702.     int stopped;
  703.     int core;
  704.  
  705.     TRACE(("dowait(%d) called\n", block));
  706.     do {
  707.         pid = waitproc(block, &status);
  708.         TRACE(("wait returns %d, status=%d\n", pid, status));
  709.     } while (pid == -1 && errno == EINTR);
  710.     if (pid <= 0)
  711.         return pid;
  712.     INTOFF;
  713.     thisjob = NULL;
  714.     for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
  715.         if (jp->used) {
  716.             done = 1;
  717.             stopped = 1;
  718.             for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
  719.                 if (sp->pid == -1)
  720.                     continue;
  721.                 if (sp->pid == pid) {
  722.                     TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
  723.                     sp->status = status;
  724.                     thisjob = jp;
  725.                 }
  726.                 if (sp->status == -1)
  727.                     stopped = 0;
  728.                 else if ((sp->status & 0377) == 0177)
  729.                     done = 0;
  730.             }
  731.             if (stopped) {        /* stopped or done */
  732.                 int state = done? JOBDONE : JOBSTOPPED;
  733.                 if (jp->state != state) {
  734.                     TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
  735.                     jp->state = state;
  736. #if JOBS
  737.                     if (done && curjob == jp - jobtab + 1)
  738.                         curjob = 0;        /* no current job */
  739. #endif
  740.                 }
  741.             }
  742.         }
  743.     }
  744.     INTON;
  745.     if (! rootshell || ! iflag || (job && thisjob == job)) {
  746. #if JOBS
  747.         if ((status & 0xFF) == 0177)
  748.             status >>= 8;
  749. #endif
  750.         core = status & 0x80;
  751.         status &= 0x7F;
  752.         if (status != 0 && status != SIGINT && status != SIGPIPE) {
  753.             if (thisjob != job)
  754.                 outfmt(out2, "%d: ", pid);
  755. #if JOBS
  756.             if (status == SIGTSTP && rootshell && iflag)
  757.                 outfmt(out2, "%%%d ", job - jobtab + 1);
  758. #endif
  759.             if (status <= MAXSIG && sigmesg[status])
  760.                 out2str(sigmesg[status]);
  761.             else
  762.                 outfmt(out2, "Signal %d", status);
  763.             if (core)
  764.                 out2str(" - core dumped");
  765.             out2c('\n');
  766.             flushout(&errout);
  767.         } else {
  768.             TRACE(("Not printing status: status=%d\n", status));
  769.         }
  770.     } else {
  771.         TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
  772.         if (thisjob)
  773.             thisjob->changed = 1;
  774.     }
  775.     return pid;
  776. }
  777.  
  778.  
  779.  
  780. /*
  781.  * Do a wait system call.  If job control is compiled in, we accept
  782.  * stopped processes.  If block is zero, we return a value of zero
  783.  * rather than blocking.
  784.  *
  785.  * System V doesn't have a non-blocking wait system call.  It does
  786.  * have a SIGCLD signal that is sent to a process when one of it's
  787.  * children dies.  The obvious way to use SIGCLD would be to install
  788.  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
  789.  * was received, and have waitproc bump another counter when it got
  790.  * the status of a process.  Waitproc would then know that a wait
  791.  * system call would not block if the two counters were different.
  792.  * This approach doesn't work because if a process has children that
  793.  * have not been waited for, System V will send it a SIGCLD when it
  794.  * installs a signal handler for SIGCLD.  What this means is that when
  795.  * a child exits, the shell will be sent SIGCLD signals continuously
  796.  * until is runs out of stack space, unless it does a wait call before
  797.  * restoring the signal handler.  The code below takes advantage of
  798.  * this (mis)feature by installing a signal handler for SIGCLD and
  799.  * then checking to see whether it was called.  If there are any
  800.  * children to be waited for, it will be.
  801.  *
  802.  * If neither SYSV nor BSD is defined, we don't implement nonblocking
  803.  * waits at all.  In this case, the user will not be informed when
  804.  * a background process until the next time she runs a real program
  805.  * (as opposed to running a builtin command or just typing return),
  806.  * and the jobs command may give out of date information.
  807.  */
  808.  
  809. #ifdef SYSV
  810. STATIC int gotsigchild;
  811.  
  812. STATIC int onsigchild() {
  813.     gotsigchild = 1;
  814. }
  815. #endif
  816.  
  817.  
  818. STATIC int
  819. waitproc(block, status)
  820.     int *status;
  821.     {
  822. #ifdef BSD
  823.     int flags;
  824.  
  825. #if JOBS
  826.     flags = WUNTRACED;
  827. #else
  828.     flags = 0;
  829. #endif
  830.     if (block == 0)
  831.         flags |= WNOHANG;
  832.     return wait3((union wait *)status, flags, (struct rusage *)NULL);
  833. #else
  834. #ifdef SYSV
  835.     int (*save)();
  836.  
  837.     if (block == 0) {
  838.         gotsigchild = 0;
  839.         save = signal(SIGCLD, onsigchild);
  840.         signal(SIGCLD, save);
  841.         if (gotsigchild == 0)
  842.             return 0;
  843.     }
  844.     return wait(status);
  845. #else
  846.     if (block == 0)
  847.         return 0;
  848.     return wait(status);
  849. #endif
  850. #endif
  851. }
  852.  
  853.  
  854.  
  855. /*
  856.  * Return a string identifying a command (to be printed by the
  857.  * jobs command.
  858.  */
  859.  
  860. STATIC char *cmdnextc;
  861. STATIC int cmdnleft;
  862. STATIC void cmdtxt(), cmdputs();
  863.  
  864. STATIC char *
  865. commandtext(n)
  866.     union node *n;
  867.     {
  868.     char *name;
  869.  
  870.     cmdnextc = name = ckmalloc(50);
  871.     cmdnleft = 50 - 4;
  872.     cmdtxt(n);
  873.     *cmdnextc = '\0';
  874.     return name;
  875. }
  876.  
  877.  
  878. STATIC void
  879. cmdtxt(n)
  880.     union node *n;
  881.     {
  882.     union node *np;
  883.     struct nodelist *lp;
  884.     char *p;
  885.     int i;
  886.     char s[2];
  887.  
  888.     switch (n->type) {
  889.     case NSEMI:
  890.         cmdtxt(n->nbinary.ch1);
  891.         cmdputs("; ");
  892.         cmdtxt(n->nbinary.ch2);
  893.         break;
  894.     case NAND:
  895.         cmdtxt(n->nbinary.ch1);
  896.         cmdputs(" && ");
  897.         cmdtxt(n->nbinary.ch2);
  898.         break;
  899.     case NOR:
  900.         cmdtxt(n->nbinary.ch1);
  901.         cmdputs(" || ");
  902.         cmdtxt(n->nbinary.ch2);
  903.         break;
  904.     case NPIPE:
  905.         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
  906.             cmdtxt(lp->n);
  907.             if (lp->next)
  908.                 cmdputs(" | ");
  909.         }
  910.         break;
  911.     case NSUBSHELL:
  912.         cmdputs("(");
  913.         cmdtxt(n->nredir.n);
  914.         cmdputs(")");
  915.         break;
  916.     case NREDIR:
  917.     case NBACKGND:
  918.         cmdtxt(n->nredir.n);
  919.         break;
  920.     case NIF:
  921.         cmdputs("if ");
  922.         cmdtxt(n->nif.test);
  923.         cmdputs("; then ");
  924.         cmdtxt(n->nif.ifpart);
  925.         cmdputs("...");
  926.         break;
  927.     case NWHILE:
  928.         cmdputs("while ");
  929.         goto until;
  930.     case NUNTIL:
  931.         cmdputs("until ");
  932. until:
  933.         cmdtxt(n->nbinary.ch1);
  934.         cmdputs("; do ");
  935.         cmdtxt(n->nbinary.ch2);
  936.         cmdputs("; done");
  937.         break;
  938.     case NFOR:
  939.         cmdputs("for ");
  940.         cmdputs(n->nfor.var);
  941.         cmdputs(" in ...");
  942.         break;
  943.     case NCASE:
  944.         cmdputs("case ");
  945.         cmdputs(n->ncase.expr->narg.text);
  946.         cmdputs(" in ...");
  947.         break;
  948.     case NDEFUN:
  949.         cmdputs(n->narg.text);
  950.         cmdputs("() ...");
  951.         break;
  952.     case NCMD:
  953.         for (np = n->ncmd.args ; np ; np = np->narg.next) {
  954.             cmdtxt(np);
  955.             if (np->narg.next)
  956.                 cmdputs(" ");
  957.         }
  958.         for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
  959.             cmdputs(" ");
  960.             cmdtxt(np);
  961.         }
  962.         break;
  963.     case NARG:
  964.         cmdputs(n->narg.text);
  965.         break;
  966.     case NTO:
  967.         p = ">";  i = 1;  goto redir;
  968.     case NAPPEND:
  969.         p = ">>";  i = 1;  goto redir;
  970.     case NTOFD:
  971.         p = ">&";  i = 1;  goto redir;
  972.     case NFROM:
  973.         p = "<";  i = 0;  goto redir;
  974.     case NFROMFD:
  975.         p = "<&";  i = 0;  goto redir;
  976. redir:
  977.         if (n->nfile.fd != i) {
  978.             s[0] = n->nfile.fd + '0';
  979.             s[1] = '\0';
  980.             cmdputs(s);
  981.         }
  982.         cmdputs(p);
  983.         if (n->type == NTOFD || n->type == NFROMFD) {
  984.             s[0] = n->ndup.dupfd + '0';
  985.             s[1] = '\0';
  986.             cmdputs(s);
  987.         } else {
  988.             cmdtxt(n->nfile.fname);
  989.         }
  990.         break;
  991.     case NHERE:
  992.     case NXHERE:
  993.         cmdputs("<<...");
  994.         break;
  995.     default:
  996.         cmdputs("???");
  997.         break;
  998.     }
  999. }
  1000.  
  1001.  
  1002.  
  1003. STATIC void
  1004. cmdputs(s)
  1005.     char *s;
  1006.     {
  1007.     register char *p, *q;
  1008.     register char c;
  1009.     int subtype = 0;
  1010.  
  1011.     if (cmdnleft <= 0)
  1012.         return;
  1013.     p = s;
  1014.     q = cmdnextc;
  1015.     while ((c = *p++) != '\0') {
  1016.         if (c == CTLESC)
  1017.             *q++ = *p++;
  1018.         else if (c == CTLVAR) {
  1019.             *q++ = '$';
  1020.             if (--cmdnleft > 0)
  1021.                 *q++ = '{';
  1022.             subtype = *p++;
  1023.         } else if (c == '=' && subtype != 0) {
  1024.             *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
  1025.             subtype = 0;
  1026.         } else if (c == CTLENDVAR) {
  1027.             *q++ = '}';
  1028.         } else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE)
  1029.             cmdnleft++;        /* ignore it */
  1030.         else
  1031.             *q++ = c;
  1032.         if (--cmdnleft <= 0) {
  1033.             *q++ = '.';
  1034.             *q++ = '.';
  1035.             *q++ = '.';
  1036.             break;
  1037.         }
  1038.     }
  1039.     cmdnextc = q;
  1040. }
  1041.